#include<iostream>
#include<unistd.h>
#include"Task.hpp"
#include"LockGuard.hpp"
#include"Thread.hpp"

const int n = 5;

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

template<class T>
class ThreadPool
{
private:
  ThreadPool(int num)
    :_num(num)
  {
    pthread_mutex_init(&_mutex,nullptr);
    pthread_cond_init(&_cond,nullptr);
  }
  ThreadPool(const ThreadPool<T>& tp) = delete;
  void operator=(const ThreadPool<T>& tp) = delete;
public:
  static ThreadPool<T>* GetInstance(int num = n)
  {
    if(instance == nullptr)//减少加锁的次数，提高效率
    {
      LockGuard Lock(&instance_mutex);
      if(instance == nullptr)
      {
        instance = new ThreadPool(num);
        instance->Init();
        instance->Start();
      }
    }
    return instance;
  }

  void Wait()
  {
    pthread_cond_wait(&_cond,&_mutex);
  }

  void WakeUp()
  {
    pthread_cond_signal(&_cond);
  }

  pthread_mutex_t* GetLock()//这里有无GetLock，对于用LockGuard对_mutex加锁，没有区别。成员函数可以访问成员变量，不论十分私有，并且返回的都是_mutex地址，所以没有区别
  {
    return &_mutex;
  }

  void push(const T& key)
  {
    LockGuard Lock(GetLock());
    _task.push(key);
    WakeUp();   
  }

  void pop(T& key)
  {
    LockGuard Lock(GetLock());
    while(_task.empty())
    {
      Wait();
    }
    key = _task.front();
    _task.pop();
  }

  static void* ThreadRoutine(void* args)
  {
    ThreadPool<T>* tp = static_cast<ThreadPool<T>*>(args);
    while(true)
    {
      T t;
      tp->pop(t);
      t();
      LockGuard Lock(&mutex);
      cout << "某个线程运行 : " << t.FormatRes() << endl;
    }
    return nullptr;
  }

  void Init()
  {
    for(int i = 0; i < _num; ++i)
    {
      _threads.push_back(Thread(i,ThreadRoutine,this));
    }
  }

  void Start()
  {
    for(auto& thread : _threads)
    {
      thread.run();
    }
  }

  ~ThreadPool()
  {
    for(auto& thread : _threads)
    {
      thread.join();
    }
    pthread_mutex_destroy(&_mutex);
    pthread_cond_destroy(&_cond);
  }
private:
  vector<Thread> _threads;
  queue<T> _task;
  int _num;
  pthread_mutex_t _mutex;
  pthread_cond_t _cond;

  static ThreadPool<T>* instance;
  static pthread_mutex_t instance_mutex;
};

template<class T>
ThreadPool<T>* ThreadPool<T>::instance = nullptr;

template<class T>
pthread_mutex_t ThreadPool<T>::instance_mutex = PTHREAD_MUTEX_INITIALIZER;


